﻿using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using System.IO.Ports;
using System.Collections;

namespace NetduinoPlusControllerMain
{
    public class Ping
    {
        private TristatePort _port;

        // Pass in the pin to which the rangefinder is attached.
        public Ping(Cpu.Pin pin)
        {
            _port = new TristatePort(pin, false, false, ResistorModes.Disabled);
        }

        // Returns distance in mm
        public int mm_Distance()
        {

            // First we need to pulse the port ... high, low.  It seems to work fine, without adding any delay.
            _port.Active = true;                // Put port in write mode
            _port.Write(true);                  // Pulse pin
            _port.Write(false);

            _port.Active = false;                        // Put port in read mode;    
            bool v1 = false;
            while (v1 == false) { v1 = _port.Read(); }   // Wait for line to go high.
            long tick1 = System.DateTime.Now.Ticks;      // Save start ticks.

            bool v2 = true;
            while (v2 == true) { v2 = _port.Read(); }    // Wait for line to go low.
            long tick2 = System.DateTime.Now.Ticks;      // Save end ticks. 

            int ticks = (int)(tick2 - tick1);
            // Now, just have to convert ticks to mm
            //   Per wikipedia: speed of sound, dry air, 20 deg C, 343 m /s
            //   Per msdn: one .NET "Tick" = 0.1 micro seconds.
            // Which works out to ... 
            // ... 1 mm of travel each 29.15 ticks
            // ... divide by 2 for round-trip ... 58.3 ticks per mm

            return ticks * 10 / 583;
        }
    }

    public class Program
    {
        static SerialPort com;
        static Ping ping;
        public static void Main()
        {
            Queue distanceValues = new Queue();
            com = new SerialPort(SerialPorts.COM1, 9600, Parity.None, 8, StopBits.One);
            com.Open();
            com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
            //Ping ping = new Ping(Pins.GPIO_PIN_D7);
            ping = new Ping(Pins.GPIO_PIN_D7);
            int lastDistanceMeasurement = 0;
            int transMeasurementDeltaToleranceThreshold = 1;
            while (true)
            {
                int currentDistanceMeasurementInCentimeters = ping.mm_Distance() / 10;
                if (currentDistanceMeasurementInCentimeters != lastDistanceMeasurement)
                {
                    if (System.Math.Abs(lastDistanceMeasurement - currentDistanceMeasurementInCentimeters) <= transMeasurementDeltaToleranceThreshold)
                    {
                        //Debug.Print("MINOR Distance measurement changed from " + lastDistanceMeasurement.ToString() + " to " + currentDistanceMeasurementInCentimeters.ToString() + "cm and is within tolerance of " + transMeasurementDeltaToleranceThreshold.ToString());
                    }
                    else
                    {
                        CrossPlatform.CrossPlatformMessagesForSumpPump sumpPumpMessages = new CrossPlatform.CrossPlatformMessagesForSumpPump();
                        Debug.Print("NEW Distance measurement changed from " + lastDistanceMeasurement.ToString() + " to " + currentDistanceMeasurementInCentimeters.ToString() + "cm");
                        if (currentDistanceMeasurementInCentimeters < 10)
                        {
                            // send an alarm event
                            string destanceEvent =
                                sumpPumpMessages.createSumpPumpEventMessage(DateTime.Now, "Alarm", "Distance was too small at " + currentDistanceMeasurementInCentimeters + " cm");
                            Debug.Print(destanceEvent);
                            com.Write(System.Text.Encoding.UTF8.GetBytes(destanceEvent), 0, destanceEvent.Length);
                        }
                        if (currentDistanceMeasurementInCentimeters > 15)
                        {
                            // send an alarm event
                            string destanceEvent =
                                sumpPumpMessages.createSumpPumpEventMessage(DateTime.Now, "Alarm", "Distance was too large at " + currentDistanceMeasurementInCentimeters + " cm");
                            Debug.Print(destanceEvent);
                            com.Write(System.Text.Encoding.UTF8.GetBytes(destanceEvent), 0, destanceEvent.Length);
                        }

                        lastDistanceMeasurement = currentDistanceMeasurementInCentimeters; // capture new value

                        // send status data with new value
                        string currentDistance = sumpPumpMessages.createSumpPumpStatusMessage(currentDistanceMeasurementInCentimeters, -47);
                        Debug.Print(currentDistance);
                        com.Write(System.Text.Encoding.UTF8.GetBytes(currentDistance), 0, currentDistance.Length);
                    }
                }
                else
                {
                    //Debug.Print("Unchanged Distance measurement = " + currentDistanceMeasurementInCentimeters.ToString() + "cm");
                }
                //distanceValues.Enqueue(cm);
                //Debug.Print(cm.ToString() + "cm");
                //Thread.Sleep(5000);
                Thread.Sleep(2000);
            }
        }

        static void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] bytes = new byte[1];
            com.Read(bytes, 0, bytes.Length);

            if (bytes[0] == 'd')
            {
                int cm = ping.mm_Distance() / 10;
                //string currentDistance = "Distance = " + cm.ToString() + "cm";
                CrossPlatform.CrossPlatformMessagesForSumpPump sumpPumpMessages = new CrossPlatform.CrossPlatformMessagesForSumpPump();
                string currentDistance = sumpPumpMessages.createSumpPumpStatusMessage(cm, -27);
                Debug.Print(currentDistance);
                com.Write(System.Text.Encoding.UTF8.GetBytes(currentDistance), 0, currentDistance.Length);
            }
            else
            {
                com.Write(bytes, 0, bytes.Length);
            }
        }
    }
}




